using AutoMapper;
using CoreManager.Models.DTOs;
using CoreManager.Models.Entities;
using CoreManager.Repository.Repositories;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace CoreManager.Services.Roles
{
    /// <summary>
    /// 角色服务实现
    /// </summary>
    public class RoleService : IRoleService
    {
        private readonly IRepository<Role> _roleRepository;
        private readonly IRepository<RoleMenu> _roleMenuRepository;
        private readonly IRepository<Menu> _menuRepository;
        private readonly IMapper _mapper;
        private readonly ILogger<RoleService> _logger;

        public RoleService(
            IRepository<Role> roleRepository,
            IRepository<RoleMenu> roleMenuRepository,
            IRepository<Menu> menuRepository,
            IMapper mapper,
            ILogger<RoleService> logger)
        {
            _roleRepository = roleRepository;
            _roleMenuRepository = roleMenuRepository;
            _menuRepository = menuRepository;
            _mapper = mapper;
            _logger = logger;
        }

        /// <summary>
        /// 获取角色列表
        /// </summary>
        public async Task<ApiResponse<List<RoleDto>>> GetRolesAsync(RoleQueryDto query)
        {
            try
            {
                var queryable = _roleRepository.GetQueryable();

                // 角色名称模糊查询
                if (!string.IsNullOrWhiteSpace(query.RoleName))
                {
                    queryable = queryable.Where(r => r.RoleName.Contains(query.RoleName));
                }

                // 角色编码模糊查询
                if (!string.IsNullOrWhiteSpace(query.RoleCode))
                {
                    queryable = queryable.Where(r => r.RoleCode.Contains(query.RoleCode));
                }

                // 状态筛选
                if (query.Status.HasValue)
                {
                    queryable = queryable.Where(r => r.Status == query.Status.Value);
                }

                var roles = await queryable
                    .OrderBy(r => r.Sort)
                    .ThenBy(r => r.CreateTime)
                    .ToListAsync();

                var roleDtos = new List<RoleDto>();
                foreach (var role in roles)
                {
                    var roleDto = _mapper.Map<RoleDto>(role);
                    
                    // 获取角色关联的菜单权限
                    var roleMenus = await _roleMenuRepository.GetQueryable()
                        .Where(rm => rm.RoleId == role.Id)
                        .ToListAsync();
                    
                    roleDto.MenuIds = roleMenus.Select(rm => rm.MenuId).ToList();
                    
                    roleDtos.Add(roleDto);
                }

                return ApiResponse<List<RoleDto>>.Success(roleDtos);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取角色列表失败");
                return ApiResponse<List<RoleDto>>.Fail("获取角色列表失败");
            }
        }

        /// <summary>
        /// 根据ID获取角色详情
        /// </summary>
        public async Task<ApiResponse<RoleDto>> GetRoleByIdAsync(int id)
        {
            try
            {
                var role = await _roleRepository.GetByIdAsync(id);
                if (role == null)
                {
                    return ApiResponse<RoleDto>.Fail("角色不存在");
                }

                var roleDto = _mapper.Map<RoleDto>(role);
                
                // 获取角色关联的菜单权限
                var roleMenus = await _roleMenuRepository.GetQueryable()
                    .Where(rm => rm.RoleId == id)
                    .ToListAsync();
                
                roleDto.MenuIds = roleMenus.Select(rm => rm.MenuId).ToList();
                
                // 获取菜单详情
                if (roleDto.MenuIds.Any())
                {
                    var menus = await _menuRepository.GetQueryable()
                        .Where(m => roleDto.MenuIds.Contains(m.Id))
                        .ToListAsync();
                    
                    roleDto.Menus = _mapper.Map<List<MenuDto>>(menus);
                }

                return ApiResponse<RoleDto>.Success(roleDto);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取角色详情失败，ID: {Id}", id);
                return ApiResponse<RoleDto>.Fail("获取角色详情失败");
            }
        }

        /// <summary>
        /// 创建角色
        /// </summary>
        public async Task<ApiResponse<RoleDto>> CreateRoleAsync(CreateRoleDto createDto)
        {
            try
            {
                // 检查角色编码是否已存在
                var existsResult = await CheckRoleCodeExistsAsync(createDto.RoleCode);
                if (existsResult.Data)
                {
                    return ApiResponse<RoleDto>.Fail("角色编码已存在");
                }

                var role = _mapper.Map<Role>(createDto);
                role.CreateTime = DateTime.Now;

                var roleId = await _roleRepository.InsertAsync(role);
                role.Id = roleId;

                // 分配菜单权限
                if (createDto.MenuIds.Any())
                {
                    foreach (var menuId in createDto.MenuIds)
                    {
                        var roleMenu = new RoleMenu
                        {
                            RoleId = roleId,
                            MenuId = menuId,
                            CreateTime = DateTime.Now
                        };
                        await _roleMenuRepository.InsertAsync(roleMenu);
                    }
                }

                var roleDto = _mapper.Map<RoleDto>(role);
                roleDto.MenuIds = createDto.MenuIds;

                return ApiResponse<RoleDto>.Success(roleDto);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "创建角色失败");
                return ApiResponse<RoleDto>.Fail("创建角色失败");
            }
        }

        /// <summary>
        /// 更新角色
        /// </summary>
        public async Task<ApiResponse<RoleDto>> UpdateRoleAsync(int id, UpdateRoleDto updateDto)
        {
            try
            {
                var role = await _roleRepository.GetByIdAsync(id);
                if (role == null)
                {
                    return ApiResponse<RoleDto>.Fail("角色不存在");
                }

                // 检查角色编码是否已存在（排除当前角色）
                var existsResult = await CheckRoleCodeExistsAsync(updateDto.RoleCode, id);
                if (existsResult.Data)
                {
                    return ApiResponse<RoleDto>.Fail("角色编码已存在");
                }

                _mapper.Map(updateDto, role);
                role.UpdateTime = DateTime.Now;

                await _roleRepository.UpdateAsync(role);

                // 更新菜单权限关联
                // 先删除原有关联
                var existingRoleMenus = await _roleMenuRepository.GetQueryable()
                    .Where(rm => rm.RoleId == id)
                    .ToListAsync();
                
                foreach (var roleMenu in existingRoleMenus)
                {
                    await _roleMenuRepository.DeleteAsync(roleMenu.Id);
                }

                // 添加新的关联
                if (updateDto.MenuIds.Any())
                {
                    foreach (var menuId in updateDto.MenuIds)
                    {
                        var roleMenu = new RoleMenu
                        {
                            RoleId = id,
                            MenuId = menuId,
                            CreateTime = DateTime.Now
                        };
                        await _roleMenuRepository.InsertAsync(roleMenu);
                    }
                }

                var roleDto = _mapper.Map<RoleDto>(role);
                roleDto.MenuIds = updateDto.MenuIds;

                return ApiResponse<RoleDto>.Success(roleDto);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "更新角色失败，ID: {Id}", id);
                return ApiResponse<RoleDto>.Fail("更新角色失败");
            }
        }

        /// <summary>
        /// 删除角色
        /// </summary>
        public async Task<ApiResponse<bool>> DeleteRoleAsync(int id)
        {
            try
            {
                var role = await _roleRepository.GetByIdAsync(id);
                if (role == null)
                {
                    return ApiResponse<bool>.Fail("角色不存在");
                }

                // 删除角色菜单关联
                var roleMenus = await _roleMenuRepository.GetQueryable()
                    .Where(rm => rm.RoleId == id)
                    .ToListAsync();
                
                foreach (var roleMenu in roleMenus)
                {
                    await _roleMenuRepository.DeleteAsync(roleMenu.Id);
                }

                // 删除角色
                await _roleRepository.DeleteAsync(id);

                return ApiResponse<bool>.Success(true);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "删除角色失败，ID: {Id}", id);
                return ApiResponse<bool>.Fail("删除角色失败");
            }
        }

        /// <summary>
        /// 批量删除角色
        /// </summary>
        public async Task<ApiResponse<bool>> BatchDeleteRolesAsync(List<int> ids)
        {
            try
            {
                var roles = await _roleRepository.GetQueryable()
                    .Where(r => ids.Contains(r.Id))
                    .ToListAsync();

                if (!roles.Any())
                {
                    return ApiResponse<bool>.Fail("没有找到要删除的角色");
                }

                // 删除角色菜单关联
                var roleMenus = await _roleMenuRepository.GetQueryable()
                    .Where(rm => ids.Contains(rm.RoleId))
                    .ToListAsync();
                
                foreach (var roleMenu in roleMenus)
                {
                    await _roleMenuRepository.DeleteAsync(roleMenu.Id);
                }

                // 删除角色
                foreach (var role in roles)
                {
                    await _roleRepository.DeleteAsync(role.Id);
                }

                return ApiResponse<bool>.Success(true);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "批量删除角色失败");
                return ApiResponse<bool>.Fail("批量删除角色失败");
            }
        }

        /// <summary>
        /// 分配角色权限
        /// </summary>
        public async Task<ApiResponse<bool>> AssignRolePermissionsAsync(AssignRolePermissionsDto assignDto)
        {
            try
            {
                var role = await _roleRepository.GetByIdAsync(assignDto.RoleId);
                if (role == null)
                {
                    return ApiResponse<bool>.Fail("角色不存在");
                }

                // 删除原有权限关联
                var existingRoleMenus = await _roleMenuRepository.GetQueryable()
                    .Where(rm => rm.RoleId == assignDto.RoleId)
                    .ToListAsync();
                
                foreach (var roleMenu in existingRoleMenus)
                {
                    await _roleMenuRepository.DeleteAsync(roleMenu.Id);
                }

                // 添加新的权限关联
                if (assignDto.MenuIds.Any())
                {
                    foreach (var menuId in assignDto.MenuIds)
                    {
                        var roleMenu = new RoleMenu
                        {
                            RoleId = assignDto.RoleId,
                            MenuId = menuId,
                            CreateTime = DateTime.Now
                        };
                        await _roleMenuRepository.InsertAsync(roleMenu);
                    }
                }

                return ApiResponse<bool>.Success(true);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "分配角色权限失败");
                return ApiResponse<bool>.Fail("分配角色权限失败");
            }
        }

        /// <summary>
        /// 获取角色的菜单权限
        /// </summary>
        public async Task<ApiResponse<List<MenuDto>>> GetRoleMenusAsync(int roleId)
        {
            try
            {
                var roleMenus = await _roleMenuRepository.GetQueryable()
                    .Where(rm => rm.RoleId == roleId)
                    .ToListAsync();

                var menuIds = roleMenus.Select(rm => rm.MenuId).ToList();
                
                var menus = await _menuRepository.GetQueryable()
                    .Where(m => menuIds.Contains(m.Id))
                    .OrderBy(m => m.Sort)
                    .ToListAsync();

                var menuDtos = _mapper.Map<List<MenuDto>>(menus);

                return ApiResponse<List<MenuDto>>.Success(menuDtos);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取角色菜单权限失败，角色ID: {RoleId}", roleId);
                return ApiResponse<List<MenuDto>>.Fail("获取角色菜单权限失败");
            }
        }

        /// <summary>
        /// 检查角色编码是否存在
        /// </summary>
        public async Task<ApiResponse<bool>> CheckRoleCodeExistsAsync(string roleCode, int? excludeId = null)
        {
            try
            {
                var query = _roleRepository.GetQueryable()
                    .Where(r => r.RoleCode == roleCode);

                if (excludeId.HasValue)
                {
                    query = query.Where(r => r.Id != excludeId.Value);
                }

                var exists = await query.AnyAsync();
                return ApiResponse<bool>.Success(exists);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "检查角色编码是否存在失败");
                return ApiResponse<bool>.Fail("检查角色编码是否存在失败");
            }
        }

        /// <summary>
        /// 更新角色状态
        /// </summary>
        public async Task<ApiResponse<bool>> UpdateRoleStatusAsync(int id, int status)
        {
            try
            {
                var role = await _roleRepository.GetByIdAsync(id);
                if (role == null)
                {
                    return ApiResponse<bool>.Fail("角色不存在");
                }

                role.Status = status;
                role.UpdateTime = DateTime.Now;

                await _roleRepository.UpdateAsync(role);

                return ApiResponse<bool>.Success(true);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "更新角色状态失败，ID: {Id}", id);
                return ApiResponse<bool>.Fail("更新角色状态失败");
            }
        }
    }
}
